package com.uit.httt04.duongvanlam.facedetection.activity;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_objdetect.*;
import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.CvMemStorage;
import com.googlecode.javacv.cpp.opencv_core.CvRect;
import com.googlecode.javacv.cpp.opencv_core.CvSeq;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_objdetect.CvHaarClassifierCascade;
import com.uit.httt04.duongvanlam.facedetection.R;
import com.uit.httt04.duongvanlam.facedetection.algorithm.Algorithm;
import com.uit.httt04.duongvanlam.facedetection.algorithm.Lda_2d_R;
import com.uit.httt04.duongvanlam.facedetection.algorithm.Pca_2d_R;
import com.uit.httt04.duongvanlam.facedetection.extend.CameraPreview;
import com.uit.httt04.duongvanlam.facedetection.imageprocessing.ImageProcessing;
import com.uit.httt04.duongvanlam.facedetection.utils.ClassFile;
import com.uit.httt04.duongvanlam.facedetection.utils.ClassLogger;
import com.uit.httt04.duongvanlam.facedetection.utils.ClassToast;
import com.uit.httt04.duongvanlam.facedetection.utils.Configuration;
import com.uit.httt04.duongvanlam.facedetection.xml.AlgorithmXML;
import com.uit.httt04.duongvanlam.facedetection.xml.IDToNameXML;
import com.uit.httt04.duongvanlam.facedetection.xml.MatrixXML;
import com.uit.httt04.duongvanlam.facedetection.xml.ObjectXML;
import com.uit.httt04.duongvanlam.facedetection.xml.ProjectedObjectXML;
import com.uit.httt04.duongvanlam.facedetection.xml.TrainingXML;

import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

@SuppressLint({ "SimpleDateFormat", "DefaultLocale", "UseSparseArrays" })
public class MainAcivity extends Activity implements OnClickListener, PreviewCallback {
	private String TAG = "MainAcivity";
	// <-- UI
	private Button btnTest;
	private Button btnRecord;
	private Button btnTrain;
	private Button btnReset;
	private EditText txtName;
	private CameraPreview myCamera;
	// UI -->
	// <-- Camera & Detection
	private boolean startCamera;
	private CvHaarClassifierCascade classifierCascade;
	private CvMemStorage memStorage;
	// Camera & Detection -->
	// <-- Back Button
	private long timeStampLastPressBackButton;
	private final int total2TimesPressBackButton = 1000; // 1000ms = 1s
	// Back Button -->
	// <-- Support
	private int maxFacesToDetetForTraining;
	private int maxImagesPerFaceToTraining;
	private boolean isRecording;
	private int countImages;
	private String personName;

	// Support -->

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		try {
			Log.d(TAG, "onCreate");
			super.onCreate(savedInstanceState);
			this.setContentView(R.layout.main_acivity);
			//
			ClassFile.CreateAppFolder();
			// Get max faces to detection
			this.maxFacesToDetetForTraining = Configuration.maxFacesToDetetForTraining;
			//
			this.maxImagesPerFaceToTraining = Configuration.maxImagesPerFaceToTraining;
			//
			File xmlFile = ClassFile.getCascadeXmlFile(this.getApplicationContext());
			if (xmlFile.exists() == true) {
				classifierCascade = new CvHaarClassifierCascade(cvLoad(xmlFile.getAbsolutePath()));
				if (classifierCascade != null) {
					memStorage = cvCreateMemStorage(0);

					if (this.memStorage == null) {
						throw new RuntimeException("Can't initialize");
					}
				}
			}
			//
			this.startCamera = false;
			//
			this.timeStampLastPressBackButton = 0;
			//
			this.countImages = 0;
			//
			this.personName = "";
			//
			this.isRecording = false;

			//
			// <-- Initialize view
			//

			this.btnRecord = (Button) this.findViewById(R.id.main_acivity_btnrecord);
			this.btnRecord.setOnClickListener(this);

			this.btnTrain = (Button) this.findViewById(R.id.main_acivity_btntrain);
			this.btnTrain.setOnClickListener(this);

			this.btnReset = (Button) this.findViewById(R.id.main_acivity_btnreset);
			this.btnReset.setOnClickListener(this);

			this.btnTest = (Button) this.findViewById(R.id.main_acivity_btntest);
			this.btnTest.setOnClickListener(this);

			this.txtName = (EditText) this.findViewById(R.id.main_acivity_txtpersonname);

			this.myCamera = (CameraPreview) this.findViewById(R.id.main_acivity_camerapreview);
			this.myCamera.Load(this, this, false, Configuration.cameraHeight, Configuration.cameraWidth, Configuration.frontCamera);//

			// Initialize view -->
			//

			/*
			//
			// <-- For testing
			//
			Intent i = new Intent(context, UnlockActivity.class);
			i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			startActivity(i);
			//
			// For testing -->
			//
			*/

			/*
			//
			// <-- Edit after finish
			//
			if (ClassService.isService_AfterBootCompleteRunning(this.getApplicationContext()) == false)
			{
				Intent service = new Intent(this.getApplicationContext(), Service_AfterBootComplete.class);
				this.getApplicationContext().startService(service);
			}
			*/
			// Edit after finish -->
			//
			//
		} catch (Exception e) {
			ClassToast.Show(this.getApplicationContext(), "Error", true);
			ClassLogger.Write(this.getClass().getName(), "onCreate", e.toString());
			e.printStackTrace();
			this.finish();
		}
	}

	@Override
	protected void onDestroy() {
		try {
			Log.d(TAG, "onDestroy");

			if (this.classifierCascade != null)
				cvReleaseHaarClassifierCascade(this.classifierCascade);
			if (this.memStorage != null)
				cvReleaseMemStorage(this.memStorage);

			super.onDestroy();

		} catch (Exception e) {
			ClassToast.Show(this.getApplicationContext(), "Error", true);
			ClassLogger.Write(this.getClass().getName(), "onDestroy", e.toString());
			e.printStackTrace();
		}
	}

	@Override
	protected void onResume() {
		try {
			Log.d(TAG, "onResume");
			super.onResume();
		} catch (Exception e) {
			ClassToast.Show(this.getApplicationContext(), "Error", true);
			ClassLogger.Write(this.getClass().getName(), "onResume", e.toString());
		}
	}

	@Override
	protected void onPause() {
		try {
			Log.d(TAG, "onPause");
			super.onPause();
		} catch (Exception e) {
			ClassToast.Show(this.getApplicationContext(), "Error", true);
			ClassLogger.Write(this.getClass().getName(), "onPause", e.toString());
		}
	}

	@Override
	protected void onRestart() {
		try {
			Log.d(TAG, "onRestart");
			super.onRestart();
		} catch (Exception e) {
			ClassToast.Show(this.getApplicationContext(), "Error", true);
			ClassLogger.Write(this.getClass().getName(), "onRestart", e.toString());
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main_acivity, menu);
		return true;
	}

	@Override
	public void onClick(View v) {
		try {
			switch (v.getId()) {
			case R.id.main_acivity_btnreset: {
				this.BtnResetClick();
			}
				break;

			case R.id.main_acivity_btntrain: {
				this.Training();
			}
				break;

			case R.id.main_acivity_btnrecord: {
				this.BtnRecordClick();
			}
				break;

			case R.id.main_acivity_btntest: {
				Intent i = new Intent(this.getApplicationContext(), UnlockActivity.class);
				i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				startActivity(i);
			}
				break;
			}
		} catch (Exception e) {
			if (this.btnRecord.isEnabled() == false)
				this.btnRecord.setEnabled(true);

			if (this.btnReset.isEnabled() == false)
				this.btnReset.setEnabled(true);

			if (this.btnTrain.isEnabled() == false)
				this.btnTrain.setEnabled(true);

			Toast.makeText(this.getApplicationContext(), "Error", Toast.LENGTH_SHORT).show();
			ClassLogger.Write(MainAcivity.this.getClass().getName(), "onClick", e.toString());
			e.printStackTrace();
		}
	}

	@Override
	public void onPreviewFrame(byte[] data, Camera camera) {
		Log.d(TAG, "onPreviewFrame, this.personName: " + this.personName);

		if (this.startCamera == true && this.personName != null && this.personName.equalsIgnoreCase("") == false) {
			try {
				if (data.length > 0 && camera != null) {
					// get timestamp for set file's name
					long timeStamp = new Date().getTime();
					// camera's size
					Size cameraSize = camera.getParameters().getPreviewSize();
					int height = cameraSize.height;
					int width = cameraSize.width;
					// Convert YCrCr to RGB
					CvMat dataYCrCb = cvCreateMat(height * 3 / 2, width, CV_8UC1);
					dataYCrCb.getByteBuffer().put(data);
					CvMat dataRGB = ImageProcessing.YCrCbToRGB(dataYCrCb, height, width);

					/*
					//
					// <-- Save file for testing
					//
					IplImage imageRGB = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
					imageRGB = cvGetImage(dataRGB, imageRGB);
					ImageProcessing.SaveImageFromIplImage(imageRGB, Configuration.trainingFolderPath + "/" + timeStamp + "_imageRGB" + Configuration.AllowedExt);
					//
					int[] dataRGB2 = new int[height * width];
					ImageProcessing.YCrCbToRGB2(dataRGB2, data, width, height);
					Bitmap imageRGB2 = Bitmap.createBitmap(dataRGB2, width, height, Config.ARGB_8888);
					ImageProcessing.SaveImageFromBitmap(imageRGB2, Configuration.trainingFolderPath + "/" + timeStamp + "_imageRGB2" + Configuration.AllowedExt);
					//
					// Save file for testing -->
					//
					*/

					// <-- Detection faces
					Detection(dataRGB, height, width, Configuration.trainingFolderPath + "/" + this.personName + "_" + timeStamp);
					// Detection faces -->

					//cvReleaseImage(imageRGB);
					cvReleaseMat(dataYCrCb);
					cvReleaseMat(dataRGB);
				}
			} catch (Exception e) {
				ClassLogger.Write(this.getClass().getName(), "onPreviewFrame", e.toString());
				e.printStackTrace();
			} finally {
				try {
					this.myCamera.getFrame();
				} catch (Exception e) {
					ClassLogger.Write(this.getClass().getName(), "onPreviewFrame", e.toString());
					e.printStackTrace();
				}
			}
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (this.startCamera == true)
			return true;

		if (keyCode == KeyEvent.KEYCODE_BACK) {
			if ((event.getDownTime() - this.timeStampLastPressBackButton) < this.total2TimesPressBackButton) {
				this.finish();
			} else {
				this.timeStampLastPressBackButton = event.getDownTime();
				Toast.makeText(this.getApplicationContext(), getResources().getString(R.string.close_Application), Toast.LENGTH_SHORT).show();
			}

			return true;
		}

		return super.onKeyDown(keyCode, event);
	}

	private void BtnResetClick() throws Exception {
		try {
			AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainAcivity.this);
			alertDialogBuilder.setTitle(R.string.alertDialogBuilder_BtnReset_Title);
			alertDialogBuilder.setMessage(R.string.alertDialogBuilder_BtnReset_Message);
			alertDialogBuilder.setNegativeButton(R.string.alertDialogBuilder_BtnReset_NegativeButton, new AlertDialog.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.cancel();
				}
			});
			alertDialogBuilder.setPositiveButton(R.string.alertDialogBuilder_BtnReset_PositiveButton, new AlertDialog.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					try {
						File trainingFolder = new File(Configuration.trainingFolderPath);
						if (trainingFolder.exists()) {
							ClassFile.DeleteRecursive(trainingFolder);
							ClassFile.CreateAppFolder();
						}

						Toast.makeText(MainAcivity.this, getResources().getString(R.string.complete), Toast.LENGTH_SHORT).show();
					} catch (Exception e) {
						ClassLogger.Write(this.getClass().getName(), "onClick Of PositiveButton", e.toString());
						e.printStackTrace();
					}
				}
			});

			AlertDialog alertDialog = alertDialogBuilder.create();
			alertDialog.show();
		} catch (Exception e) {
			throw e;
		}
	}

	private void BtnRecordClick() throws Exception {
		try {
			if (isRecording == false) {
				this.personName = this.txtName.getText().toString().trim().toLowerCase();

				if (this.personName.equalsIgnoreCase(""))
					Toast.makeText(this.getApplicationContext(), getResources().getString(R.string.alert_btnTraining_noname), Toast.LENGTH_SHORT).show();
				else {
					this.btnTrain.setEnabled(false);
					this.btnReset.setEnabled(false);
					isRecording = true;
					if (this.btnRecord.getText().equals(this.getResources().getString(R.string.btnrecordStop)) == false)
						this.btnRecord.setText(this.getResources().getString(R.string.btnrecordStop));

					this.StartCamera();
				}
			} else {
				this.StopCamera();

				Toast.makeText(this.getApplicationContext(), this.personName + " has " + this.countImages + " images", Toast.LENGTH_SHORT).show();

				this.personName = "";
				this.countImages = 0;
				this.txtName.setText("");

				if (this.btnRecord.getText().equals(this.getResources().getString(R.string.btnrecord)) == false)
					this.btnRecord.setText(this.getResources().getString(R.string.btnrecord));
				this.btnTrain.setEnabled(true);
				this.btnReset.setEnabled(true);
				isRecording = false;
			}

		} catch (Exception e) {
			throw e;
		}
	}

	private void StartCamera() throws Exception {
		try {
			this.myCamera.startPreview();
			this.startCamera = true;
		} catch (Exception e) {
			throw e;
		}
	}

	private void StopCamera() throws Exception {
		try {
			this.myCamera.stopPreview();
			this.startCamera = false;
		} catch (Exception e) {
			throw e;
		}
	}

	private void Training() throws Exception {
		try {
			// <-- UI
			this.btnRecord.setEnabled(false);
			this.btnReset.setEnabled(false);
			// UI -->

			// <-- Delete old file
			File xmlFileTraining = new File(Configuration.TrainingFilePath);
			if (xmlFileTraining.exists() == true)
				xmlFileTraining.delete();
			// Delete old file -->

			//
			//
			//

			String trainingFolderPath = Configuration.trainingFolderPath;
			int height = Configuration.imageHeightTraining;
			int width = Configuration.imageWidthTraining;
			int NEigenvector = Configuration.NEigenvector;
			char matrixDataSplitBy = Configuration.MatrixDataSplitBy;
			//
			//
			//

			//
			// <-- Pca_2d_R
			//

			AlgorithmXML pca2drXML = null;
			Pca_2d_R pca2dr = null;
			try {
				long TimestampStartingPca_2d_R = 0;
				long TimestampEndingPca_2d_R = 0;
				long TrainingLengthPca_2d_R = 0;

				TimestampStartingPca_2d_R = System.currentTimeMillis();

				pca2dr = new Pca_2d_R();
				pca2dr.Load(trainingFolderPath, height, width);
				pca2dr.Train();
				pca2dr.Project(new int[] { NEigenvector });

				TimestampEndingPca_2d_R = System.currentTimeMillis();
				TrainingLengthPca_2d_R = TimestampEndingPca_2d_R - TimestampStartingPca_2d_R;

				pca2drXML = new AlgorithmXML();
				pca2drXML.setAlgorithmName(pca2dr.getClass().getName());
				pca2drXML.setTimestampStarting(TimestampStartingPca_2d_R);
				pca2drXML.setTrainingLengthByMilliseconds(TrainingLengthPca_2d_R);
				pca2drXML.setTrainingFolderPath(trainingFolderPath);
				pca2drXML.setImageHeight(height);
				pca2drXML.setImageWidth(width);
				pca2drXML.setTotalAmountOfImages(pca2dr.getAmountOfObjects());
				pca2drXML.setTotalAmountOfFaces(pca2dr.getAmountOfFaces());

				List<ObjectXML> objects = new ArrayList<ObjectXML>();
				for (int i = 0; i < pca2dr.getAmountOfObjects(); i++) {
					ObjectXML objectXML = new ObjectXML();
					objectXML.setImagePath(pca2dr.getListObjects().get(i).getImagePath());
					objectXML.setPersonName(pca2dr.getListObjects().get(i).getPersonName());

					objects.add(objectXML);
				}

				pca2drXML.setObjects(objects);
				pca2drXML.setEigenvectorMaxN(NEigenvector);
				pca2drXML.setMatrixDataSplitBy(matrixDataSplitBy);

				MatrixXML eigenvectorMatrix = new MatrixXML();
				eigenvectorMatrix.setHeight(pca2dr.getProjectedEigenvect().rows());
				eigenvectorMatrix.setWidth(pca2dr.getProjectedEigenvect().cols());
				eigenvectorMatrix.setData(MatrixXML.MatrixToString(matrixDataSplitBy, pca2dr.getProjectedEigenvect()));
				pca2drXML.setEigenvectorMatrix(eigenvectorMatrix);

				MatrixXML eigenvalueMatrix = new MatrixXML();
				eigenvalueMatrix.setHeight(pca2dr.getEigenVal().rows());
				eigenvalueMatrix.setWidth(pca2dr.getEigenVal().cols());
				eigenvalueMatrix.setData(MatrixXML.MatrixToString(matrixDataSplitBy, pca2dr.getEigenVal()));
				pca2drXML.setEigenvalueMatrix(eigenvalueMatrix);

				List<ProjectedObjectXML> projectedObjects = new ArrayList<ProjectedObjectXML>();
				for (int i = 0; i < pca2dr.getAmountOfProjectedObjects(); i++) {
					MatrixXML projectedObjectMatrix = new MatrixXML();
					projectedObjectMatrix.setHeight(pca2dr.getProjectedListObjects().get(i).getMatrix().rows());
					projectedObjectMatrix.setWidth(pca2dr.getProjectedListObjects().get(i).getMatrix().cols());
					projectedObjectMatrix.setData(MatrixXML.MatrixToString(matrixDataSplitBy, pca2dr.getProjectedListObjects().get(i).getMatrix()));

					ProjectedObjectXML projectedObjectXML = new ProjectedObjectXML();
					projectedObjectXML.setImagePath(pca2dr.getProjectedListObjects().get(i).getImagePath());
					projectedObjectXML.setPersonName(pca2dr.getProjectedListObjects().get(i).getPersonName());
					projectedObjectXML.setMatrix(projectedObjectMatrix);

					projectedObjects.add(projectedObjectXML);
				}

				pca2drXML.setProjectedObjects(projectedObjects);

				pca2drXML.setAllowedExt(pca2dr.getAllowedExt());

				List<IDToNameXML> autoID = new ArrayList<IDToNameXML>();
				for (Map.Entry<Integer, String> e : pca2dr.getAutoIdToName().entrySet()) {
					autoID.add(new IDToNameXML(e.getKey(), e.getValue()));
				}
				pca2drXML.setAutoID(autoID);
			} catch (Exception e) {
				ClassLogger.Write(this.getClass().getName(), "Training of Pca_2d_R", e.toString());
				e.printStackTrace();
			}
			//
			// Pca_2d_R -->
			//

			//
			// <-- Lda_2d_R
			//

			AlgorithmXML lda2drXML = null;
			Lda_2d_R lda2dr = null;
			try {
				long TimestampStartingLda_2d_R = 0;
				long TimestampEndingLda_2d_R = 0;
				long TrainingLengthLda_2d_R = 0;

				TimestampStartingLda_2d_R = System.currentTimeMillis();

				lda2dr = new Lda_2d_R();
				if (pca2dr != null)
					lda2dr.LoadFromAlgorithm(pca2dr);
				else
					lda2dr.Load(trainingFolderPath, height, width);
				lda2dr.Train();
				lda2dr.Project(new int[] { NEigenvector });

				TimestampEndingLda_2d_R = System.currentTimeMillis();
				TrainingLengthLda_2d_R = TimestampEndingLda_2d_R - TimestampStartingLda_2d_R;

				lda2drXML = new AlgorithmXML();
				lda2drXML.setAlgorithmName(lda2dr.getClass().getName());
				lda2drXML.setTimestampStarting(TimestampStartingLda_2d_R);
				lda2drXML.setTrainingLengthByMilliseconds(TrainingLengthLda_2d_R);
				lda2drXML.setTrainingFolderPath(trainingFolderPath);
				lda2drXML.setImageHeight(height);
				lda2drXML.setImageWidth(width);
				lda2drXML.setTotalAmountOfImages(lda2dr.getAmountOfObjects());
				lda2drXML.setTotalAmountOfFaces(lda2dr.getAmountOfFaces());

				List<ObjectXML> objects = new ArrayList<ObjectXML>();
				for (int i = 0; i < lda2dr.getAmountOfObjects(); i++) {
					ObjectXML objectXML = new ObjectXML();
					objectXML.setImagePath(lda2dr.getListObjects().get(i).getImagePath());
					objectXML.setPersonName(lda2dr.getListObjects().get(i).getPersonName());

					objects.add(objectXML);
				}

				lda2drXML.setObjects(objects);
				lda2drXML.setEigenvectorMaxN(NEigenvector);
				lda2drXML.setMatrixDataSplitBy(matrixDataSplitBy);

				MatrixXML eigenvectorMatrix = new MatrixXML();
				eigenvectorMatrix.setHeight(lda2dr.getProjectedEigenvect().rows());
				eigenvectorMatrix.setWidth(lda2dr.getProjectedEigenvect().cols());
				eigenvectorMatrix.setData(MatrixXML.MatrixToString(matrixDataSplitBy, lda2dr.getProjectedEigenvect()));
				lda2drXML.setEigenvectorMatrix(eigenvectorMatrix);

				MatrixXML eigenvalueMatrix = new MatrixXML();
				eigenvalueMatrix.setHeight(lda2dr.getEigenVal().rows());
				eigenvalueMatrix.setWidth(lda2dr.getEigenVal().cols());
				eigenvalueMatrix.setData(MatrixXML.MatrixToString(matrixDataSplitBy, lda2dr.getEigenVal()));
				lda2drXML.setEigenvalueMatrix(eigenvalueMatrix);

				List<ProjectedObjectXML> projectedObjects = new ArrayList<ProjectedObjectXML>();
				for (int i = 0; i < lda2dr.getAmountOfProjectedObjects(); i++) {
					MatrixXML projectedObjectMatrix = new MatrixXML();
					projectedObjectMatrix.setHeight(lda2dr.getProjectedListObjects().get(i).getMatrix().rows());
					projectedObjectMatrix.setWidth(lda2dr.getProjectedListObjects().get(i).getMatrix().cols());
					projectedObjectMatrix.setData(MatrixXML.MatrixToString(matrixDataSplitBy, lda2dr.getProjectedListObjects().get(i).getMatrix()));

					ProjectedObjectXML projectedObjectXML = new ProjectedObjectXML();
					projectedObjectXML.setImagePath(lda2dr.getProjectedListObjects().get(i).getImagePath());
					projectedObjectXML.setPersonName(lda2dr.getProjectedListObjects().get(i).getPersonName());
					projectedObjectXML.setMatrix(projectedObjectMatrix);

					projectedObjects.add(projectedObjectXML);
				}
				lda2drXML.setProjectedObjects(projectedObjects);

				lda2drXML.setAllowedExt(lda2dr.getAllowedExt());

				List<IDToNameXML> autoID = new ArrayList<IDToNameXML>();
				for (Map.Entry<Integer, String> e : lda2dr.getAutoIdToName().entrySet()) {
					autoID.add(new IDToNameXML(e.getKey(), e.getValue()));
				}
				lda2drXML.setAutoID(autoID);
			} catch (Exception e) {
				ClassLogger.Write(this.getClass().getName(), "Training of Lda_2d_R", e.toString());
				e.printStackTrace();
			}
			//
			// Lda_2d_R -->
			//

			List<AlgorithmXML> algorithmsXML = new ArrayList<AlgorithmXML>();
			if (pca2drXML != null)
				algorithmsXML.add(pca2drXML);
			if (lda2drXML != null)
				algorithmsXML.add(lda2drXML);
			TrainingXML trainingXML = new TrainingXML();
			trainingXML.setListAlgorithm(algorithmsXML);
			TrainingXML.WriteToXmlFile(trainingXML, Configuration.trainingFileName, Configuration.trainingFolderPath);
			trainingXML = null;

			List<Algorithm> algorithms = new ArrayList<Algorithm>();
			if (pca2dr != null)
				algorithms.add(pca2dr);
			if (lda2dr != null)
				algorithms.add(lda2dr);
			((MyApplication) this.getApplication()).setAlgorithms(algorithms);

			// <-- UI
			this.btnRecord.setEnabled(true);
			this.btnReset.setEnabled(true);
			// UI -->
		} catch (Exception e) {
			throw e;
		}
	}

	private void Detection(CvMat ImageData, int height, int width, String OutputImagePath) throws Exception {
		try {
			if (ImageData != null && ImageData.empty() == false) {
				IplImage originalImage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
				originalImage = cvGetImage(ImageData, originalImage);
				//
				IplImage grayImage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
				cvCvtColor(originalImage, grayImage, CV_BGR2GRAY);
				//

				CvSeq faces = null;
				if (this.memStorage != null && this.classifierCascade != null) {
					faces = cvHaarDetectObjects(grayImage, this.classifierCascade, this.memStorage, 1.1, 3, CV_HAAR_FEATURE_MAX | CV_HAAR_SCALE_IMAGE | CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH | CV_HAAR_DO_CANNY_PRUNING, cvSize(Configuration.imageWidthMinSize, Configuration.imageHeightMinSize), cvSize(Configuration.imageWidthMaxSize, Configuration.imageHeightMaxSize));
				}

				if (faces != null) {
					for (int i = 0; i < faces.total() && i < this.maxFacesToDetetForTraining; i++) {
						CvRect rect = new CvRect(cvGetSeqElem(faces, i));
						if (rect.width() >= Configuration.imageWidthMinSize && rect.width() <= Configuration.imageWidthMaxSize && rect.height() >= Configuration.imageHeightMinSize && rect.height() <= Configuration.imageHeightMaxSize) {
							//
							IplImage cropped = cvCreateImage(cvSize(rect.width(), rect.height()), originalImage.depth(), originalImage.nChannels());
							cvSetImageROI(originalImage, rect);
							cvCopy(originalImage, cropped);
							//
							//
							// <-- Save image
							//
							ImageProcessing.SaveImageFromIplImage(cropped, OutputImagePath + "." + i + Configuration.SavedExt);
							this.countImages++;
							//
							// Save image -->
							//
							//
							cvResetImageROI(originalImage);

							if (this.countImages == this.maxImagesPerFaceToTraining) {
								break;
							}
						} // End minWidth<=rect.width()<=maxWidth && minHeigh<=rect.height()<=maxHeight
					} // End i < faces.total()
				} // End faces != null

				if (faces != null)
					cvClearSeq(faces);
				if (this.memStorage != null)
					cvClearMemStorage(this.memStorage);
				if (grayImage != null)
					cvReleaseImage(grayImage);
				if (originalImage != null)
					cvReleaseImage(originalImage);

				if (this.countImages == this.maxImagesPerFaceToTraining) {
					this.StopCamera();
				}
			}
		} catch (Exception e) {
			throw e;
		}
	}
}
